home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / math / ast51src.zip / XGENERAL.C < prev    next >
C/C++ Source or Header  |  1995-12-31  |  25KB  |  877 lines

  1. /*
  2. ** Astrolog (Version 5.10) File: xgeneral.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (Astara@msn.com). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 12/27/1995.
  35. */
  36.  
  37. #include "astrolog.h"
  38.  
  39.  
  40. #ifdef GRAPH
  41. /*
  42. ******************************************************************************
  43. ** Core Graphic Procedures.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Set the current color to use in drawing on the screen or bitmap array. */
  48.  
  49. void DrawColor(col)
  50. KI col;
  51. {
  52. #ifdef WIN
  53.   HPEN hpenT;
  54. #endif
  55.  
  56.   if (gi.fFile) {
  57. #ifdef PS
  58.     if (gs.fPS) {
  59.       if (gi.kiCur != col) {
  60.         PsStrokeForce();      /* Render existing path with current color */
  61.         fprintf(gi.file, "%.2f %.2f %.2f c\n",
  62.           (real)RGBR(rgbbmp[col])/255.0, (real)RGBG(rgbbmp[col])/255.0,
  63.           (real)RGBB(rgbbmp[col])/255.0);
  64.       }
  65.     }
  66. #endif
  67. #ifdef META
  68.     if (gs.fMeta)
  69.       gi.kiLineDes = col;
  70. #endif
  71.   }
  72. #ifdef X11
  73.   else
  74.     XSetForeground(gi.disp, gi.gc, rgbind[col]);
  75. #endif
  76. #ifdef WIN
  77.   else {
  78.     if (gi.kiCur != col) {
  79.       hpenT = wi.hpen;
  80.       wi.hpen = CreatePen(PS_SOLID, 1, (COLORREF)rgbbmp[col]);
  81.       SelectObject(wi.hdc, wi.hpen);
  82.       if (hpenT != (HPEN)NULL)
  83.         DeleteObject(hpenT);
  84.     }
  85.   }
  86. #endif
  87. #ifdef MSG
  88.   else
  89.     _setcolor(col);
  90. #endif
  91. #ifdef BGI
  92.   else
  93.     setcolor(col);
  94. #endif
  95.   gi.kiCur = col;
  96. }
  97.  
  98.  
  99. /* Set a single point on the screen. This is the most basic graphic function */
  100. /* and is called by all the more complex routines. Based on what mode we are */
  101. /* in, we either set a cell in the bitmap array or a pixel on the window.    */
  102.  
  103. void DrawPoint(x, y)
  104. int x, y;
  105. {
  106.   if (gi.fFile) {
  107.     if (gs.fBitmap) {
  108.       /* Force the coordinates to be within the bounds of the bitmap array. */
  109.  
  110.       if (x < 0)
  111.         x = 0;
  112.       else if (x >= gs.xWin)
  113.         x = gs.xWin-1;
  114.       if (y < 0)
  115.         y = 0;
  116.       else if (y >= gs.yWin)
  117.         y = gs.yWin-1;
  118.       if (gi.yBand) {
  119.         y -= gi.yOffset;
  120.         if (y < 0 || y >= gi.yBand)
  121.           return;
  122.       }
  123.       BmSet(gi.bm, x, y, gi.kiCur);
  124.     }
  125. #ifdef PS
  126.     else if (gs.fPS) {
  127.       DrawColor(gi.kiCur);
  128.       PsLineCap(fTrue);
  129.       fprintf(gi.file, "%d %d d\n", x, y);
  130.       PsStroke(2);
  131.     }
  132. #endif
  133. #ifdef META
  134.     else {
  135.       gi.kiFillDes = gi.kiCur;
  136.       MetaSelect();
  137.       MetaEllipse(x-gi.nPenWid/2, y-gi.nPenWid/2,
  138.         x+gi.nPenWid/2, y+gi.nPenWid/2);
  139.     }
  140. #endif
  141.   }
  142. #ifdef X11
  143.   else
  144.     XDrawPoint(gi.disp, gi.pmap, gi.gc, x, y);
  145. #endif
  146. #ifdef WIN
  147.   else {
  148.     if (wi.hdcPrint == hdcNil)
  149.       SetPixel(wi.hdc, x, y, (COLORREF)rgbbmp[gi.kiCur]);
  150.     else {
  151.       MoveTo(wi.hdc, x, y);
  152.       LineTo(wi.hdc, x, y);
  153.     }
  154.   }
  155. #endif
  156. #ifdef MSG
  157.   else
  158.     _setpixel(gi.xOffset + x, gi.yOffset + y);
  159. #endif
  160. #ifdef BGI
  161.   else
  162.     putpixel(gi.xOffset + x, gi.yOffset + y, gi.kiCur);
  163. #endif
  164. }
  165.  
  166.  
  167. /* Draw dot a little larger than just a single pixel at specified location. */
  168.  
  169. void DrawSpot(x, y)
  170. int x, y;
  171. {
  172. #ifdef PS
  173.   if (gs.fPS) {
  174.     PsLineWidth((int)(gi.rLineWid*3.0));
  175.     DrawPoint(x, y);
  176.     PsLineWidth((int)(gi.rLineWid/3.0));
  177.     return;
  178.   }
  179. #endif
  180. #ifdef META
  181.   if (gs.fMeta) {
  182.     gi.kiFillDes = gi.kiCur;
  183.     MetaSelect();
  184.     MetaEllipse(x-gi.nPenWid, y-gi.nPenWid, x+gi.nPenWid, y+gi.nPenWid);
  185.     return;
  186.   }
  187. #endif
  188.   DrawPoint(x, y);
  189.   DrawPoint(x, y-1);
  190.   DrawPoint(x-1, y);
  191.   DrawPoint(x+1, y);
  192.   DrawPoint(x, y+1);
  193. }
  194.  
  195.  
  196. /* Draw a filled in block, defined by the corners of its rectangle. */
  197.  
  198. void DrawBlock(x1, y1, x2, y2)
  199. int x1, y1, x2, y2;
  200. {
  201.   int x, y;
  202.  
  203.   if (gi.fFile) {
  204.     if (gs.fBitmap) {
  205.       if (gi.yBand) {
  206.         y1 -= gi.yOffset;
  207.         if (y1 < 0)
  208.           y1 = 0;
  209.         y2 -= gi.yOffset;
  210.         if (y2 > gi.yBand)
  211.           y2 = gi.yBand-1;
  212.       }
  213.       for (y = y1; y <= y2; y++)           /* For bitmap, we have to  */
  214.         for (x = x1; x <= x2; x++)         /* just fill in the array. */
  215.           BmSet(gi.bm, x, y, gi.kiCur);
  216.     }
  217. #ifdef PS
  218.     else if (gs.fPS) {
  219.       DrawColor(gi.kiCur);
  220.       fprintf(gi.file, "%d %d %d %d rf\n",
  221.         Max(x1-gi.nPenWid/4, 0), Max(y1-gi.nPenWid/4, 0),
  222.         x2-x1+gi.nPenWid/4, y2-y1+gi.nPenWid/4);
  223.     }
  224. #endif
  225. #ifdef META
  226.     else {
  227.       gi.kiFillDes = gi.kiCur;
  228.       MetaSelect();
  229.       MetaRectangle(x1-gi.nPenWid/2, y1-gi.nPenWid/2,
  230.         x2+gi.nPenWid/2, y2+gi.nPenWid/2);
  231.     }
  232. #endif
  233.   }
  234. #ifdef X11
  235.   else
  236.     XFillRectangle(gi.disp, gi.pmap, gi.gc, x1, y1, x2-x1, y2-y1);
  237. #endif
  238. #ifdef WIN
  239.   else {
  240.     wi.hbrush = CreateSolidBrush((COLORREF)rgbbmp[gi.kiCur]);
  241.     SelectObject(wi.hdc, wi.hbrush);
  242.     PatBlt(wi.hdc, x1, y1, x2-x1 + 1, y2-y1 + 1, PATCOPY);
  243.     SelectObject(wi.hdc, GetStockObject(NULL_BRUSH));
  244.     DeleteObject(wi.hbrush);
  245.   }
  246. #endif
  247. #ifdef MSG
  248.   else
  249.     _rectangle(_GFILLINTERIOR,
  250.       gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
  251. #endif
  252. #ifdef BGI
  253.   else {
  254.     setfillstyle(SOLID_FILL, gi.kiCur);
  255.     bar(gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
  256.   }
  257. #endif
  258. }
  259.  
  260.  
  261. /* Draw a rectangle on the screen with specified thickness. This is just   */
  262. /* like DrawBlock() except that we are only drawing the edges of the area. */
  263.  
  264. void DrawBox(x1, y1, x2, y2, xsiz, ysiz)
  265. int x1, y1, x2, y2, xsiz, ysiz;
  266. {
  267. #ifdef META
  268.   if (gs.fMeta)
  269.     /* For thin boxes in metafiles, we can just output one rectangle record */
  270.     /* instead of drawing each side separately as we have to do otherwise.  */
  271.     if (xsiz <= 1 && ysiz <= 1) {
  272.       gi.kiFillDes = kNull;          /* Specify a hollow fill brush. */
  273.       MetaSelect();
  274.       MetaRectangle(x1, y1, x2, y2);
  275.       return;
  276.     }
  277. #endif
  278.   DrawBlock(x1, y1, x2, y1 + ysiz - 1);
  279.   DrawBlock(x1, y1 + ysiz, x1 + xsiz - 1, y2 - ysiz);
  280.   DrawBlock(x2 - xsiz + 1, y1 + ysiz, x2, y2 - ysiz);
  281.   DrawBlock(x1, y2 - ysiz + 1, x2, y2);
  282. }
  283.  
  284.  
  285. /* Clear and erase the graphics screen or bitmap contents. */
  286.  
  287. void DrawClearScreen()
  288. {
  289. #ifdef PS
  290.   if (gs.fPS) {
  291.     /* For PostScript charts first output page orientation information. */
  292.     if (!gi.fEps) {
  293.       if (gs.nOrient == 0)
  294.         gs.nOrient = gs.xWin > gs.yWin ? -1 : 1;
  295.       if (gs.nOrient < 0) {
  296.         /* chartx and charty are reversed for Landscape mode. */
  297.         fprintf(gi.file, "%d %d translate\n",
  298.           ((int)(gs.xInch*72.0+rRound) + gs.yWin)/2,
  299.           ((int)(gs.yInch*72.0+rRound) + gs.xWin)/2);
  300.         fprintf(gi.file, "-90 rotate\n");
  301.       } else {
  302.         /* Most charts are in Portrait mode */
  303.         fprintf(gi.file, "%d %d translate\n",
  304.           ((int)(gs.xInch*72.0+rRound) - gs.xWin)/2,
  305.           ((int)(gs.yInch*72.0+rRound) + gs.yWin)/2);
  306.       }
  307.     } else
  308.       fprintf(gi.file, "0 %d translate\n", gs.yWin);
  309.     fprintf(gi.file, "1 -1 scale\n");
  310.     gs.nScale *= PSMUL; gs.xWin *= PSMUL; gs.yWin *= PSMUL; gi.nScale *= PSMUL;
  311.     fprintf(gi.file, "1 %d div dup scale\n", PSMUL);
  312.   }
  313. #endif
  314. #ifdef META
  315.   if (gs.fMeta)
  316.     MetaInit();    /* For metafiles first go write our header information. */
  317. #endif
  318.  
  319.   /* Don't actually erase the screen if the -Xj switch is in effect. */
  320.   if (gs.fJetTrail)
  321.     return;
  322.  
  323. #ifdef MSG
  324.   if (!gi.fFile)
  325.     _clearscreen(_GCLEARSCREEN);
  326. #endif
  327. #ifdef BGI
  328.   if (!gi.fFile)
  329.     clearviewport();
  330. #endif
  331.   DrawColor(gi.kiOff);
  332.   DrawBlock(0, 0, gs.xWin - 1, gs.yWin - 1);    /* Clear bitmap screen. */
  333. }
  334.  
  335.  
  336. /* Draw a line on the screen, specified by its endpoints. In addition, we */
  337. /* have specified a skip factor, which allows us to draw dashed lines.    */
  338.  
  339. void DrawDash(x1, y1, x2, y2, skip)
  340. int x1, y1, x2, y2, skip;
  341. {
  342.   int x = x1, y = y1, xadd, yadd, yinc, xabs, yabs, i, j = 0;
  343.  
  344.   if (skip < 0)
  345.     skip = 0;
  346. #ifdef ISG
  347.   if (!gi.fFile) {
  348.     if (!skip) {
  349. #ifdef X11
  350.       /* For non-dashed X window lines, let's have the Xlib do it for us. */
  351.  
  352.       XDrawLine(gi.disp, gi.pmap, gi.gc, x1, y1, x2, y2);
  353. #endif
  354. #ifdef WIN
  355.       /* For Windows lines, we have to manually draw the last pixel. */
  356.  
  357.       MoveTo(wi.hdc, x1, y1);
  358.       LineTo(wi.hdc, x2, y2);
  359.       SetPixel(wi.hdc, x2, y2, (COLORREF)rgbbmp[gi.kiCur]);
  360. #endif
  361. #ifdef PCG
  362.       /* For non-dashed lines, let's have the graphics library do it for us. */
  363.  
  364.       PcMoveTo(gi.xOffset + x1, gi.yOffset + y1);
  365.       PcLineTo(gi.xOffset + x2, gi.yOffset + y2);
  366. #endif
  367.       return;
  368.     }
  369.   }
  370. #endif /* ISG */
  371.  
  372. #ifdef PS
  373.   if (gs.fPS) {
  374.  
  375.     /* For PostScript charts we can save file size if we output a LineTo  */
  376.     /* command when the start vertex is the same as the end vertex of the */
  377.     /* previous line drawn, instead of writing out both vertices.         */
  378.  
  379.     PsLineCap(fTrue);
  380.     PsDash(skip);
  381.     if (gi.xPen != x1 || gi.yPen != y1)
  382.       fprintf(gi.file, "%d %d %d %d l\n", x1, y1, x2, y2);
  383.     else
  384.       fprintf(gi.file, "%d %d t\n", x2, y2);
  385.     gi.xPen = x2; gi.yPen = y2;
  386.     PsStroke(2);
  387.     return;
  388.   }
  389. #endif
  390.  
  391. #ifdef META
  392.   if (gs.fMeta) {
  393.  
  394.     /* For metafile charts we can really save file size for consecutive */
  395.     /* lines sharing endpoints by consolidating them into a PolyLine.   */
  396.  
  397.     if (gi.xPen != x1 || gi.yPen != y1) {
  398.       gi.kiLineDes = (gi.kiLineDes & 15) + 16*(skip > 3 ? 3 : skip);
  399.       MetaSelect();
  400.       gi.pwPoly = gi.pwMetaCur;
  401.       MetaRecord(8, 0x325);      /* Polyline */
  402.       MetaWord(2); MetaWord(x1); MetaWord(y1);
  403.     } else {
  404.       *gi.pwPoly += 2;
  405.       (*(gi.pwPoly+3))++;
  406.       /* Note: We should technically update the max record size in the   */
  407.       /* file header if need be here too, but it doesn't seem necessary. */
  408.     }
  409.     MetaWord(x2); MetaWord(y2);
  410.     gi.xPen = x2; gi.yPen = y2;
  411.     return;
  412.   }
  413. #endif
  414.  
  415.   /* If none of the above cases hold, we have to draw the line dot by dot. */
  416.  
  417.   xadd = x2 - x1 >= 0 ? 1 : 3;
  418.   yadd = y2 - y1 >= 0 ? 2 : 4;
  419.   xabs = abs(x2 - x1);
  420.   yabs = abs(y2 - y1);
  421.  
  422.   /* Technically what we're doing here is drawing a line which is more    */
  423.   /* horizontal then vertical. We always increment x by 1, and increment  */
  424.   /* y whenever a fractional variable passes a certain amount. For lines  */
  425.   /* that are more vertical than horizontal, we just swap x and y coords. */
  426.  
  427.   if (xabs < yabs) {
  428.     SwapN(xadd, yadd);
  429.     SwapN(xabs, yabs);
  430.   }
  431.   yinc = (xabs >> 1) - ((xabs & 1 ^ 1) && xadd > 2);
  432.   for (i = xabs + 1; i; i--) {
  433.     if (j < 1)
  434.       DrawPoint(x, y);
  435.     j = j < skip ? j+1 : 0;
  436.     switch (xadd) {
  437.     case 1: x++; break;
  438.     case 2: y++; break;
  439.     case 3: x--; break;
  440.     case 4: y--; break;
  441.     }
  442.     yinc += yabs;
  443.     if (yinc - xabs >= 0) {
  444.       yinc -= xabs;
  445.       switch (yadd) {
  446.       case 1: x++; break;
  447.       case 2: y++; break;
  448.       case 3: x--; break;
  449.       case 4: y--; break;
  450.       }
  451.     }
  452.   }
  453. }
  454.  
  455.  
  456. /* Draw a normal line on the screen; however, if the x coordinates are close */
  457. /* to either of the two given bounds, then we assume that the line runs off  */
  458. /* one side and reappears on the other, so draw the appropriate two lines    */
  459. /* instead. This is used by the Ley line and astro-graph routines, which     */
  460. /* draw lines running around the world and hence off the edges of the maps.  */
  461.  
  462. void DrawWrap(x1, y1, x2, y2, xmin, xmax)
  463. int x1, y1, x2, y2, xmin, xmax;
  464. {
  465.   int xmid, ymid, i;
  466.  
  467.   if (x1 < 0) {           /* Special case for drawing world map. */
  468.     DrawPoint(x2, y2);
  469.     return;
  470.   }
  471.   xmid = (xmax-xmin) / 2;
  472.  
  473.   /* If endpoints aren't near opposite edges, just draw the line and return. */
  474.  
  475.   if (abs(x2-x1) < xmid) {
  476.     DrawLine(x1, y1, x2, y2);
  477.     return;
  478.   }
  479.   if ((i = (xmax-xmin+1) + (x1 < xmid ? x1-x2 : x2-x1)) == 0)
  480.     i = 1;
  481.  
  482.   /* Determine vertical coordinate where our line runs off edges of screen. */
  483.  
  484.   ymid = y1+(int)((real)(y2-y1)*
  485.     (x1 < xmid ? (real)(x1-xmin) : (real)(xmax-x1))/(real)i + rRound);
  486.   DrawLine(x1, y1, x1 < xmid ? xmin : xmax, ymid);
  487.   DrawLine(x2 < xmid ? xmin : xmax, ymid, x2, y2);
  488. }
  489.  
  490.  
  491. /* This routine, and its companion below, clips a line defined by its  */
  492. /* endpoints to either above some line y=c, or below some line y=c. By */
  493. /* passing in parameters in different orders, we can clip to vertical  */
  494. /* lines, too. These are used by the DrawClip() routine below.         */
  495.  
  496. void ClipLesser(x1, y1, x2, y2, s)
  497. int *x1, *y1, *x2, *y2, s;
  498. {
  499.   *x1 -= (int)((long)(*y1-s)*(*x2-*x1)/(*y2-*y1));
  500.   *y1 = s;
  501. }
  502.  
  503. void ClipGreater(x1, y1, x2, y2, s)
  504. int *x1, *y1, *x2, *y2, s;
  505. {
  506.   *x1 += (int)((long)(s-*y1)*(*x2-*x1)/(*y2-*y1));
  507.   *y1 = s;
  508. }
  509.  
  510.  
  511. /* Draw a line on the screen. This is just like DrawLine() routine earlier; */
  512. /* however, first clip the endpoints to the given viewport before drawing.  */
  513.  
  514. void DrawClip(x1, y1, x2, y2, xl, yl, xh, yh, skip)
  515. int x1, y1, x2, y2, xl, yl, xh, yh, skip;
  516. {
  517.   if (x1 < xl)
  518.     ClipLesser (&y1, &x1, &y2, &x2, xl);    /* Check left side of window. */
  519.   if (x2 < xl)
  520.     ClipLesser (&y2, &x2, &y1, &x1, xl);
  521.   if (y1 < yl)
  522.     ClipLesser (&x1, &y1, &x2, &y2, yl);    /* Check top side of window.  */
  523.   if (y2 < yl)
  524.     ClipLesser (&x2, &y2, &x1, &y1, yl);
  525.   if (x1 > xh)
  526.     ClipGreater(&y1, &x1, &y2, &x2, xh);    /* Check right of window.  */
  527.   if (x2 > xh)
  528.     ClipGreater(&y2, &x2, &y1, &x1, xh);
  529.   if (y1 > yh)
  530.     ClipGreater(&x1, &y1, &x2, &y2, yh);    /* Check bottom of window. */
  531.   if (y2 > yh)
  532.     ClipGreater(&x2, &y2, &x1, &y1, yh);
  533.   DrawDash(x1, y1, x2, y2, skip);           /* Go draw the line.       */
  534. }
  535.  
  536.  
  537. /* Draw a circle or ellipse inside the given bounding rectangle. */
  538.  
  539. void DrawEllipse(x1, y1, x2, y2)
  540. int x1, y1, x2, y2;
  541. {
  542.   int x, y, rx, ry, m, n, u, v, i;
  543.  
  544.   if (gi.fFile) {
  545.     x = (x1+x2)/2; y = (y1+y2)/2; rx = (x2-x1)/2; ry = (y2-y1)/2;
  546.     if (gs.fBitmap) {
  547.       m = x + rx; n = y;
  548.       for (i = 0; i <= nDegMax; i += DEGINC) {
  549.         u = x + (int)(((real)rx+rRound)*RCosD((real)i));
  550.         v = y + (int)(((real)ry+rRound)*RSinD((real)i));
  551.         DrawLine(m, n, u, v);
  552.         m = u; n = v;
  553.       }
  554.     }
  555. #ifdef PS
  556.     else if (gs.fPS) {
  557.       PsLineCap(fFalse);
  558.       PsStrokeForce();
  559.       PsDash(0);
  560.       fprintf(gi.file, "%d %d %d %d el\n", rx, ry, x, y);
  561.     }
  562. #endif
  563. #ifdef META
  564.     else {
  565.       gi.kiFillDes = kNull;    /* Specify a hollow fill brush. */
  566.       MetaSelect();
  567.       MetaEllipse(x1+gi.nPenWid/3, y1+gi.nPenWid/3,
  568.         x2+gi.nPenWid/3, y2+gi.nPenWid/3);
  569.     }
  570. #endif
  571.   }
  572. #ifdef X11
  573.   else
  574.     XDrawArc(gi.disp, gi.pmap, gi.gc, x1, y1, x2-x1, y2-y1, 0, nDegMax*64);
  575. #endif
  576. #ifdef WIN
  577.   else
  578.     Ellipse(wi.hdc, x1, y1, x2, y2);
  579. #endif
  580. #ifdef MSG
  581.   else
  582.     _ellipse(_GBORDER, gi.xOffset + x1, gi.yOffset + y1,
  583.       gi.xOffset + x2, gi.yOffset + y2);
  584. #endif
  585. #ifdef BGI
  586.   else
  587.     ellipse(gi.xOffset + (x1+x2)/2, gi.yOffset + (y1+y2)/2,
  588.       0, 360, (x2-x1)/2, (y2-y1)/2);
  589. #endif
  590. }
  591.  
  592.  
  593. /* Print a string of text on the graphic window at specified location. To  */
  594. /* do this we either use Astrolog's own "font" (6x10) and draw each letter */
  595. /* separately, or else specify system fonts for PostScript and metafiles.  */
  596.  
  597. void DrawSz(sz, x, y, dt)
  598. CONST char *sz;
  599. int x, y, dt;
  600. {
  601.   int s = gi.nScale, c = gi.kiCur, cch;
  602.  
  603.   cch = CchSz(sz);
  604.   if (!(dt & dtScale))
  605.     gi.nScale = gi.nScaleT;
  606.   x += gi.nScale;
  607.   if (!(dt & dtLeft))
  608.     x -= cch*xFont*gi.nScale/2;
  609.   if (dt & dtBottom)
  610.     y -= (yFont-3)*gi.nScale;
  611.   else if (!(dt & dtTop))
  612.     y -= yFont*gi.nScale/2;
  613.   if (dt & dtErase) {
  614.     DrawColor(gi.kiOff);
  615.     DrawBlock(x, y, x+xFont*gi.nScale*cch-1, y+(yFont-2)*gi.nScale);
  616.   }
  617.   DrawColor(c);
  618. #ifdef PS
  619.   if (gs.fPS && gs.fFont) {
  620.     PsFont(4);
  621.     fprintf(gi.file, "%d %d(%s)center\n",
  622.       x + xFont*gi.nScale*cch/2, y + yFont*gi.nScale/2, sz);
  623.     gi.nScale = s;
  624.     return;
  625.   }
  626. #endif
  627.   while (*sz) {
  628. #ifdef META
  629.     if (gs.fMeta && gs.fFont) {
  630.       gi.nFontDes = 3;
  631.       gi.kiTextDes = gi.kiCur;
  632.       gi.nAlignDes = 0x6 | 0 /* Center | Top */;
  633.       MetaSelect();
  634.       MetaTextOut(x, y, 1);
  635.       MetaWord(WFromBB(*sz, 0));
  636.     } else
  637. #endif
  638.       DrawTurtle(szDrawCh[(_char)*sz-' '], x, y);
  639.     x += xFont*gi.nScale;
  640.     sz++;
  641.   }
  642.   gi.nScale = s;
  643. }
  644.  
  645.  
  646. /* Draw the glyph of a sign at particular coordinates on the screen.    */
  647. /* To do this we either use Astrolog's turtle vector representation or  */
  648. /* we may specify a system font character for PostScript and metafiles. */
  649.  
  650. void DrawSign(i, x, y)
  651. int i, x, y;
  652. {
  653. #ifdef PS
  654.   if (gs.fPS && gs.fFont) {
  655.     PsFont(1);
  656.     fprintf(gi.file, "%d %d(%c)center\n", x, y, 'A' + i - 1);
  657.     return;
  658.   }
  659. #endif
  660. #ifdef META
  661.   if (gs.fMeta && gs.fFont) {
  662.     gi.nFontDes = 1;
  663.     gi.kiTextDes = gi.kiCur;
  664.     gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  665.     MetaSelect();
  666.     MetaTextOut(x, y+4*gi.nScale, 1);
  667.     MetaWord(WFromBB('^' + i - 1, 0));
  668.     return;
  669.   }
  670. #endif
  671.   DrawTurtle(szDrawSign[i], x, y);
  672. }
  673.  
  674.  
  675. /* Draw the number of a house at particular coordinates on the screen. */
  676. /* We either use a turtle vector or write a number in a system font.   */
  677.  
  678. void DrawHouse(i, x, y)
  679. int i, x, y;
  680. {
  681. #ifdef PS
  682.   if (gs.fPS && gs.fFont) {
  683.     PsFont(3);
  684.     fprintf(gi.file, "%d %d(%d)center\n", x, y, i);
  685.     return;
  686.   }
  687. #endif
  688. #ifdef META
  689.   if (gs.fMeta && gs.fFont) {
  690.     gi.nFontDes = 2;
  691.     gi.kiTextDes = gi.kiCur;
  692.     gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  693.     MetaSelect();
  694.     MetaTextOut(x, y+3*gi.nScale, 1 + (i>9));
  695.     MetaWord(WFromBB(i > 9 ? '1' : '0'+i, i > 9 ? '0'+i-10 : 0));
  696.     return;
  697.   }
  698. #endif
  699.   DrawTurtle(szDrawHouse[i], x, y);
  700. }
  701.  
  702.  
  703. /* Draw the glyph of an object at particular coordinates on the screen. */
  704.  
  705. void DrawObject(obj, x, y)
  706. int obj, x, y;
  707. {
  708.   char szGlyph[4];
  709.  
  710.   if (!gs.fLabel)    /* If we are inhibiting labels, then do nothing. */
  711.     return;
  712.  
  713.   /* For other planet centered charts, we have to remember that that     */
  714.   /* particular planet's index now represents the Earth. If we are given */
  715.   /* that index to draw, then change it so we draw the Earth instead.    */
  716.  
  717.   if (gi.nMode != gOrbit && ((obj == us.objCenter && obj > oMoo) ||
  718.     (us.objCenter == 0 && obj == oSun)))
  719.     obj = 0;
  720.   DrawColor(kObjB[obj]);
  721.   if (obj <= oNorm) {
  722. #ifdef PS
  723.     if (gs.fPS && gs.fFont == 1 && obj < uranLo && szObjectFont[obj] != ' ') {
  724.       PsFont(2);
  725.       fprintf(gi.file, "%d %d(%c)center\n", x, y, szObjectFont[obj]);
  726.       return;
  727.     }
  728. #endif
  729. #ifdef META
  730.     if (gs.fMeta && gs.fFont == 1 &&
  731.       obj < uranLo && szObjectFont[obj] != ' ') {
  732.       gi.nFontDes = 4;
  733.       gi.kiTextDes = gi.kiCur;
  734.       gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  735.       MetaSelect();
  736.       MetaTextOut(x, y+5*gi.nScale, 1);
  737.       MetaWord(WFromBB(szObjectFont[obj], 0));
  738.       return;
  739.     }
  740. #endif
  741.     DrawTurtle(szDrawObject[obj], x, y);
  742.  
  743.   /* Normally we can just go draw the glyph; however, stars don't have */
  744.   /* glyphs, so for these draw their three letter abbreviation.        */
  745.  
  746.   } else {
  747.     sprintf(szGlyph, "%c%c%c", chObj3(obj));
  748.     DrawSz(szGlyph, x, y, dtCent);
  749.   }
  750. }
  751.  
  752.  
  753. /* Draw the glyph of an aspect at particular coordinates on the screen. */
  754. /* Again we either use Astrolog's turtle vector or a system Astro font. */
  755.  
  756. void DrawAspect(asp, x, y)
  757. int asp, x, y;
  758. {
  759.   CONST char *sz;
  760.  
  761. #ifdef PS
  762.   if (gs.fPS && gs.fFont == 1 && szAspectFont[asp-1] != ' ') {
  763.     PsFont(2);
  764.     fprintf(gi.file, "%d %d(%s%c)center\n", x, y,
  765.       asp == aSSq || asp == aSes ? "\\" : "", szAspectFont[asp-1]);
  766.     return;
  767.   }
  768. #endif
  769. #ifdef META
  770.   if (gs.fMeta && gs.fFont == 1 && szAspectFont[asp-1] != ' ') {
  771.     gi.nFontDes = 4;
  772.     gi.kiTextDes = gi.kiCur;
  773.     gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  774.     MetaSelect();
  775.     MetaTextOut(x, y+5*gi.nScale, 1);
  776.     MetaWord(WFromBB(szAspectFont[asp-1], 0));
  777.     return;
  778.   }
  779. #endif
  780.   sz = szDrawAspect[asp];
  781.   if (us.fParallel) {
  782.     if (asp == aCon)
  783.       sz = "BU4BLD8BR2U8";
  784.     else if (asp = aOpp)
  785.       sz = "BU4BLD8BR2U8BF3BLL6BD2R6";
  786.   }
  787.   DrawTurtle(sz, x, y);
  788. }
  789.  
  790.  
  791. /* Convert a string segment to a positive number, updating the string to  */
  792. /* point beyond the number chars. Return 1 if the string doesn't point to */
  793. /* a numeric value. This is used by the DrawTurtle() routine to extract   */
  794. /* motion vector quantities from draw strings, e.g. the "12" in "U12".    */
  795.  
  796. int NFromPch(str)
  797. CONST char **str;
  798. {
  799.   int num = 0, i = 0;
  800.  
  801.   loop {
  802.     if (**str < '0' || **str > '9')
  803.       return num > 0 ? num : (i < 1 ? 1 : 0);
  804.     num = num*10+(**str)-'0';
  805.     (*str)++;
  806.     i++;
  807.   }
  808. }
  809.  
  810.  
  811. /* This routine is used to draw complicated objects composed of lots of line */
  812. /* segments on the screen, such as all the glyphs and coastline pieces. It   */
  813. /* is passed in a string of commands defining what to draw in relative       */
  814. /* coordinates. This is a copy of the format of the BASIC draw command found */
  815. /* in PC's. For example, "U5R10D5L10" means go up 5 dots, right 10, down 5,  */
  816. /* and left 10 - draw a box twice as wide as it is high.                     */
  817.  
  818. void DrawTurtle(sz, x0, y0)
  819. CONST char *sz;
  820. int x0, y0;
  821. {
  822.   int i, x, y, deltax, deltay;
  823.   bool fBlank, fNoupdate;
  824.   char chCmd;
  825.  
  826.   gi.xTurtle = x0; gi.yTurtle = y0;
  827.   while (chCmd = ChCap(*sz)) {
  828.     sz++;
  829.  
  830.     /* 'B' prefixing a command means just move the cursor, and don't draw. */
  831.  
  832.     if (fBlank = (chCmd == 'B')) {
  833.       chCmd = ChCap(*sz);
  834.       sz++;
  835.     }
  836.  
  837.     /* 'N' prefixing a command means don't update cursor when done drawing. */
  838.  
  839.     if (fNoupdate = (chCmd == 'N')) {
  840.       chCmd = ChCap(*sz);
  841.       sz++;
  842.     }
  843.  
  844.     /* Here we process the eight directional commands. */
  845.  
  846.     switch (chCmd) {
  847.     case 'U': deltax =  0; deltay = -1; break;      /* Up    */
  848.     case 'D': deltax =  0; deltay =  1; break;      /* Down  */
  849.     case 'L': deltax = -1; deltay =  0; break;      /* Left  */
  850.     case 'R': deltax =  1; deltay =  0; break;      /* Right */
  851.     case 'E': deltax =  1; deltay = -1; break;      /* NorthEast */
  852.     case 'F': deltax =  1; deltay =  1; break;      /* SouthEast */
  853.     case 'G': deltax = -1; deltay =  1; break;      /* SouthWest */
  854.     case 'H': deltax = -1; deltay = -1; break;      /* NorthWest */
  855.     default: PrintError("Bad draw.");       /* Shouldn't happen. */
  856.     }
  857.     x = gi.xTurtle;
  858.     y = gi.yTurtle;
  859.     i = NFromPch(&sz)*gi.nScale;    /* Figure out how far to draw. */
  860.     if (fBlank) {
  861.       gi.xTurtle += deltax*i;
  862.       gi.yTurtle += deltay*i;
  863.     } else {
  864.       gi.xTurtle += deltax*i;
  865.       gi.yTurtle += deltay*i;
  866.       DrawLine(x, y, gi.xTurtle, gi.yTurtle);
  867.       if (fNoupdate) {
  868.         gi.xTurtle = x;
  869.         gi.yTurtle = y;
  870.       }
  871.     }
  872.   }
  873. }
  874. #endif /* GRAPH */
  875.  
  876. /* xgeneral.c */
  877.